﻿using Irony.Parsing;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace AppServidor
{
    class CompiladorPista
    {
        String error;
        string ruta_compilacion;
        List<Simbolo> tablaSimbolos;
        List<ParseTreeNode> variables_espera;
        int contid;

        public string Ruta_compilacion
        {
            get { return ruta_compilacion; }
            set { ruta_compilacion = value; }
        }
        public CompiladorPista() {
            contid = 0;
        tablaSimbolos = new List<Simbolo>();
        }



       public Pista getPista(String source) {
           LanguageData lenguaje = new LanguageData(new GramaticaPista());
           Parser p = new Parser(lenguaje);
           ParseTree arbol = p.Parse(source);
           if (arbol.Root != null)
           {
               Pista pista = new Pista();


               S(arbol.Root, pista);

               return pista;
           }
           return null;
        }

       private void S(ParseTreeNode nodo, Pista objeto) {
         ParseTreeNode p=  nodo.ChildNodes[0];
           String cadena=p.Term.ToString();
           if (cadena.Equals("P"))
           {
               P(p, objeto);
              
              
           }
           else { System.Console.WriteLine("aqui paso algo raro  XD"); }
       }

       private void P(ParseTreeNode nodo, Pista objeto)
       { ///aqui viene el nombre de la pista y de las que extiende :)
           ParseTreeNode cabecera = nodo.ChildNodes[0];
           ParseTreeNode cuerpo = nodo.ChildNodes[1];
           Cabecera(cabecera,objeto);
           Cuerpo(cuerpo, objeto);
       }

       private void Cuerpo(ParseTreeNode nodo, Pista objeto) {
           ParseTreeNodeList listacuerpo = nodo.ChildNodes;
           if (listacuerpo.Count > 1)
           {
               ParseTreeNode cuerpop = listacuerpo[0];
               ParseTreeNode spista = listacuerpo[1];

               Cuerpo(cuerpop, objeto);
               Spista(spista,objeto);

           }
           else { 
               ParseTreeNode spista = listacuerpo[0];
               Spista(spista, objeto);
           }
       }

       private void Spista(ParseTreeNode nodo, Pista objeto) {
           String spistanodo = nodo.ToString();

           if (spistanodo.CompareTo("Decla_var_asig") == 0) {
               ParseTreeNodeList list = nodo.ChildNodes;
               String valor="";//metodo valor
               variables_espera.Add(nodo);
               //aun no porque no se sabe si E es una funcion
              // decla_var(list[0], objeto, valor);

           }
           else if (spistanodo.CompareTo("Decla_var") == 0){
               decla_var(nodo, objeto, "");
           }
           else if (spistanodo.CompareTo("Decla_metodos") == 0)
           {
               ParseTreeNodeList list = nodo.ChildNodes;
               decla_metodos(list[0], objeto);
           }
           else if (spistanodo.CompareTo("Decla_array") == 0)
           {

           }
           else if (spistanodo.CompareTo("Decla_array_asig") == 0)
           {

           }
           else if (spistanodo.CompareTo("Asignacion") == 0)
           {
              ParseTreeNodeList list = nodo.ChildNodes;
              Simbolo temp = tablaSimbolos.Find(x => x.Nombre.Contains(list[0].FindTokenAndGetText()));
              if (temp.TipoSim.CompareTo("variable") == 0)
              {
                  temp.Valor = "";//metodo valor
              }
           }

       }

       private void decla_metodos(ParseTreeNode nodo, Pista objeto)
       {
           ParseTreeNodeList list = nodo.ChildNodes;
           if (list[0].FindTokenAndGetText().CompareTo("Principal") == 0)
           {
               Simbolo meth = new Simbolo(contid, "Principal", "metodo", "", "", "global", objeto.Nombre, false);
               contid++;
               tablaSimbolos.Add(meth);
               //cuerpo del metodo LS
           }
           else if (list[0].FindTokenAndGetText().CompareTo("Keep") == 0)
           {

               ParseTreeNodeList hijo = list[1].ChildNodes;
               Simbolo meth = new Simbolo(contid, list[2].FindTokenAndGetText(), "metodo", hijo[0].FindTokenAndGetText(), "", "global", objeto.Nombre, true);
               contid++;
               tablaSimbolos.Add(meth);
               if (list.Count < 5)
               {
                   //cuerpo del metodo LS
               }
               else
               {
                   LDP(list[3], list[2].FindTokenAndGetText());
                   //cuerpo del metodo LS
               }

           }
           else
           {
               ParseTreeNodeList hijo = list[0].ChildNodes;
               Simbolo meth = new Simbolo(contid, list[1].FindTokenAndGetText(), "metodo", hijo[0].FindTokenAndGetText(), "", "global", objeto.Nombre, false);
               contid++;
               tablaSimbolos.Add(meth);
               if (list.Count < 4)
               {
                   //cuerpo del metodo LS
               }
               else
               {
                   LDP(list[2], list[1].FindTokenAndGetText());
                   //cuerpo del metodo LS
               }

           }
       }

       private void LS(ParseTreeNode nodo, String padre) {
           ParseTreeNodeList list = nodo.ChildNodes;
           if (list.Count == 2)
           {
               LS(list[0], padre);
               Sent(list[1], padre);
           }
           else {
               Sent(list[1], padre);
           }
       }

       private void Sent(ParseTreeNode nodo, String padre) {
           String spistanodo = nodo.ToString();

           if (spistanodo.CompareTo("Decla_var_asig") == 0)
           {
               ParseTreeNodeList list = nodo.ChildNodes;
               String valor = "";//metodo valor

               decla_var_local(list[0], padre, valor);

           }
           else if (spistanodo.CompareTo("Decla_var") == 0)
           {
               decla_var_local(nodo, padre, "");
           }
           else if (spistanodo.CompareTo("Decla_array") == 0)
           {

           }
           else if (spistanodo.CompareTo("Decla_array_asig") == 0)
           {

           }
           else if (spistanodo.CompareTo("Asignacion") == 0)
           {
               ParseTreeNodeList list = nodo.ChildNodes;
               Simbolo temp = tablaSimbolos.Find(x => x.Nombre.Contains(list[0].FindTokenAndGetText()));
               if (temp.TipoSim.CompareTo("variable") == 0)
               {
                   temp.Valor = "";//metodo valor
               }
           }
           else if (spistanodo.CompareTo("doWhile_") == 0)
           {
              
           }
           else if (spistanodo.CompareTo("If_") == 0)
           {

           }
           else if (spistanodo.CompareTo("Switch_") == 0)
           {

           }
           else if (spistanodo.CompareTo("For_") == 0)
           {
             
           }
           else if (spistanodo.CompareTo("While_") == 0)
           {

           }
           else if (spistanodo.CompareTo("CallMorF") == 0)
           {

           }
           else if (spistanodo.CompareTo("salir") == 0)
           {
              
           }
           else if (spistanodo.CompareTo("retorna") == 0)
           {

           }
       }

       private void LDP(ParseTreeNode nodo, String padre) {
           ParseTreeNodeList list = nodo.ChildNodes;
           if (list.Count == 2)
           {
               ParseTreeNodeList hijo = list[0].ChildNodes;
               Simbolo varmeth = new Simbolo(contid, list[1].FindTokenAndGetText(), "parametro", hijo[0].FindTokenAndGetText(), "", "local", padre, false);
               contid++;
               tablaSimbolos.Add(varmeth);
           }
           else {
               LDP(list[0], padre);

               ParseTreeNodeList hijo = list[1].ChildNodes;
               Simbolo varmeth = new Simbolo(contid, list[2].FindTokenAndGetText(), "parametro", hijo[0].FindTokenAndGetText(), "", "local", padre, false);
               contid++;
               tablaSimbolos.Add(varmeth);
           }
       }


       private String decla_var(ParseTreeNode nodo, Pista objeto, String val) {
           ParseTreeNodeList list = nodo.ChildNodes;
          
           if (list.Count == 2)
           {
               String infovar = decla_var(list[0], objeto,val);
               string[] words = infovar.Split(',');
               String tipovar = words[0];
               String tkeep = words[1];
               Simbolo var;
               if (tkeep.CompareTo("keep") == 0)
               {
                   var = new Simbolo(contid, list[1].FindTokenAndGetText(), "variable", tipovar, val, "global", objeto.Nombre, true);
               }
               else
               {
                   var = new Simbolo(contid, list[1].FindTokenAndGetText(), "variable", tipovar, val, "global", objeto.Nombre, false);
               }
               contid++;
               tablaSimbolos.Add(var);

               return infovar;
           }
           else if(list.Count == 3){
               ParseTreeNode hijo = list[1];
               String tipovar = hijo.ChildNodes[0].FindTokenAndGetText();
               Simbolo var = new Simbolo(contid,list[2].FindTokenAndGetText(),"variable",tipovar,val,"global",objeto.Nombre,false);
               contid++;
               tablaSimbolos.Add(var);

               return tipovar+", ";
           }
           else if (list.Count == 4)
           {
               ParseTreeNode hijo = list[2];
               String tipovar = hijo.ChildNodes[0].FindTokenAndGetText();
               Simbolo var = new Simbolo(contid, list[3].FindTokenAndGetText(), "variable", tipovar, val, "global", objeto.Nombre,true);
               contid++;
               tablaSimbolos.Add(var);

               return tipovar+",keep";
           }
           return "";
       }

       private String decla_var_local(ParseTreeNode nodo, String objeto, String val)
       {
           ParseTreeNodeList list = nodo.ChildNodes;

           if (list.Count == 2)
           {
               String infovar = decla_var_local(list[0], objeto, val);
               string[] words = infovar.Split(',');
               String tipovar = words[0];
               String tkeep = words[1];
               Simbolo var;
               if (tkeep.CompareTo("keep") == 0)
               {
                   var = new Simbolo(contid, list[1].FindTokenAndGetText(), "variable", tipovar, val, "local", objeto, true);
               }
               else
               {
                   var = new Simbolo(contid, list[1].FindTokenAndGetText(), "variable", tipovar, val, "local", objeto, false);
               }
               contid++;
               tablaSimbolos.Add(var);

               return infovar;
           }
           else if (list.Count == 3)
           {
               ParseTreeNode hijo = list[1];
               String tipovar = hijo.ChildNodes[0].FindTokenAndGetText();
               Simbolo var = new Simbolo(contid, list[2].FindTokenAndGetText(), "variable", tipovar, val, "local", objeto, false);
               contid++;
               tablaSimbolos.Add(var);

               return tipovar + ", ";
           }
           else if (list.Count == 4)
           {
               ParseTreeNode hijo = list[2];
               String tipovar = hijo.ChildNodes[0].FindTokenAndGetText();
               Simbolo var = new Simbolo(contid, list[3].FindTokenAndGetText(), "variable", tipovar, val, "local", objeto, true);
               contid++;
               tablaSimbolos.Add(var);

               return tipovar + ",keep";
           }
           return "";
       }

       private void Cabecera(ParseTreeNode nodo, Pista objeto) {
           ParseTreeNodeList lista = nodo.ChildNodes;
           if (lista.Count > 2) {
           //contiene extiende
               ParseTreeNode nombre = lista[1];//nombre
               ParseTreeNode Lextiende = lista[3];
               objeto.Nombre = nombre.FindTokenAndGetText();

               Simbolo nom = new Simbolo(contid, objeto.Nombre,"pista","","","global","",false);
               contid++;
               tablaSimbolos.Add(nom);

               List<String> lista_padres=extiende(Lextiende);
               String texto="La pista " + objeto.Nombre + " Hereda de:"+"\n";
               int i = 1;
               foreach (String padre in lista_padres) {
                  texto+="\t"+i + ")";
                  texto += padre + "\n";
               }
               MessageBox.Show(texto);
               System.Console.WriteLine(texto);
               System.Console.WriteLine("----------------------");
           }

           if (lista.Count == 2) { 
              ParseTreeNode nombre = lista[1];//nombre
              
               objeto.Nombre = nombre.FindTokenAndGetText();
           }
           System.Console.WriteLine("El nombre de la pista es: "+objeto.Nombre);
       }

       private List<String> extiende(ParseTreeNode nodo) {
           List<String> lista = new List<string>();
           extiende_recursiva(nodo, lista);
     
           return lista;
       }

       private void extiende_recursiva(ParseTreeNode nodo,List<String> x)
       {
           if (nodo.ChildNodes.Count >= 2) {
               ParseTreeNode extiende = nodo.ChildNodes[0];
               extiende_recursiva(extiende, x);
               ParseTreeNode pista_padre = nodo.ChildNodes[1];
               x.Add(pista_padre.FindTokenAndGetText());
           }
           if (nodo.ChildNodes.Count == 1)
           {
               
               ParseTreeNode pista_padre = nodo.ChildNodes[0];
               x.Add(pista_padre.FindTokenAndGetText());
           }
          
       }


    }
}
